package com.apes.scm.income.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.event.Listener;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.MapUtil;
import com.apes.scm.account.ledger.service.LedgerService;
import com.apes.scm.account.tax.repository.TaxRepository;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.contract.repository.ContractRepository;
import com.apes.scm.income.model.Income;
import com.apes.scm.income.model.IncomeItem;
import com.apes.scm.income.repository.IncomeItemRepository;
import com.apes.scm.income.repository.IncomeRepository;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.finance.model.IncomeType;
import com.apes.scm.masterdata.finance.repository.IncomeTypeRepository;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 收入服务
 *
 * @author wuq
 * @create 2018-11-27 10:49
 */
@Service
public class SupplierIncomeService extends DomainService {

    @Autowired
    private IncomeRepository incomeRepository;
    @Autowired
    private IncomeItemRepository incomeItemRepository;
    @Autowired
    private LedgerService ledgerService;
    @Autowired
    private EnumerationRepository enumerationRepository;
    @Autowired
    private PartyRoleRepository partyRoleRepository;
    @Autowired
    private IncomeTypeRepository incomeTypeRepository;
    @Autowired
    private ContractRepository contractRepository;

    public Income create(SimpleRequest request) {
        Income income = request.getO(Income.class);
        if (Objects.isNull(income.getDept())) {
            PartyRole company = income.getCompany();
            Dept dept = SpringManager.getBean(DeptRepository.class)
                    .findAll(JpaDsl.toCriteriaByEq("company", company, "deptType.id", "000006", "valid", true))
                    .stream().findFirst().orElseThrow(() -> new RuntimeException(String.format("获取公司 [%s] 的采购部门失败", company.getId())));
            income.setDept(dept);
        }
        income.computeAmount();
        income.setState("sent");
        income = incomeRepository.saveAndFlush(income);
        return income;
    }

    public String delete(SimpleRequest request) {
        Income income = request.getO(Income.class);
        incomeRepository.delete(income);
        return "删除成功！";
    }

    public Income update(SimpleRequest request) {
        Income income = request.getO(Income.class);
        if (Objects.isNull(income.getDept())) {
            Dept dept = SpringManager.getBean(DeptRepository.class)
                    .findAll(JpaDsl.toCriteriaByEq("company", income.getCompany(), "deptType.id", "000006", "valid", true))
                    .stream().findFirst().orElseThrow(() -> new RuntimeException(String.format("获取公司 [%s] 的采购部门失败", income.getCompany().getId())));
            income.setDept(dept);
        }
        return incomeRepository.saveAndFlush(income);
    }

    public Income approve(SimpleRequest request) {
        Income income = request.getO(Income.class);
        income.setState("approve");
        // 集划算审核人手动传入
        if (Objects.isNull(income.getApproveUID())) income.setApproveUID(this.getPerson(request));
        income.setApproveDate(new Date());

        extracted(income);

        boolean write = income.isWrite();
        income = incomeRepository.saveAndFlush(income);
        income.setWrite(write);
        return income;
    }

    public Income createBySystem(SimpleRequest request) {
        Income income = request.getO(Income.class);
        if (Objects.isNull(income.getDept())) {
            PartyRole company = income.getCompany();
            Dept dept = SpringManager.getBean(DeptRepository.class)
                    .findAll(JpaDsl.toCriteriaByEq("company", company, "deptType.id", "000006", "valid", true))
                    .stream().findFirst().orElseThrow(() -> new RuntimeException(String.format("获取公司 [%s] 的采购部门失败", company.getId())));
            income.setDept(dept);
        }
        income.computeAmount();
        income.setState("sent");
        income.setCreator(SpringManager.getBean(PartyRoleRepository.class).findOne("system").getId());
        income = incomeRepository.saveAndFlush(income);
        return income;
    }

    public Income approveBySystem(SimpleRequest request) {
        Income income = request.getO(Income.class);
        income.setState("approve");
        income.setApproveUID(SpringManager.getBean(PartyRoleRepository.class).findOne("system"));
        income.setApproveDate(new Date());

        extracted(income);

        return incomeRepository.saveAndFlush(income);
    }


    private void extracted(Income income) {
        ledgerService.charge(income.getCompany(), income.getDept(), income.getPartner(), income.getCooperation().getInventoryMode(),
                income.getCooperation().getAccountingMethod(), income.getInnerBusinessKey(), income.getInnerBusinessType(),
                new Date(), "discount_unsettled", income.getAmount());
    }


    /*
     * 通过合同号查找有效待收收入单明细
     * */
    public List<IncomeItem> findIsNotDoneByContractId(SimpleRequest request) {
        String supplierId = request.get("supplierId");
        String companyId = request.get("companyId");
        return incomeItemRepository.findAllBySupplierAndCompany(false, "approve", supplierId, 6L, companyId);
    }


    public List<Map<String, Object>> findIsNotDoneByPartnerId(SimpleRequest request) {
        String partnerId = request.get("partnerId");
        List<Map<String, Object>> maps = incomeItemRepository.partnerId(partnerId);
        maps.forEach(item -> {
            String incomeItemId = (String) item.get("incomeItemId");
            IncomeItem incomeItem = incomeItemRepository.byId(incomeItemId);
            item.put("incomeItem", incomeItem);
        });
        return maps;
    }

    public List<Map<String, Object>> findInvoiceItemsByPartnerIdAndDept(SimpleRequest request) {
        String deptId = request.get("deptId");
        String supplierId = request.get("supplierId");
//        Date reconcileBeginDate = DateUtil.parse(request.get("reconcileBeginDate"));
//        Date reconcileEndDate = DateUtil.parse(request.get("reconcileEndDate"));
        return incomeItemRepository.findInvoiceItemsByPartnerIdAndDept(supplierId, deptId, false);
    }

    public List<Map<String, Object>> findInvoiceItemsByPartnerIdAndCategory(SimpleRequest request) {
        String supplierId = request.get("supplierId");
        String companyId = request.get("companyId");
        List<String> category = new ArrayList<>();
        if("rebate".equals(request.get("category"))){
            category.add("rebate");
        } else if("cost".equals(request.get("category"))){
            category.add("cost");
            category.add("margin");
            category.add("002366");
            category.add("002365");
        }
            return incomeItemRepository.findInvoiceItemsByPartnerIdAndCategory(supplierId, companyId, false,request.get("cooperation"), category);
    }

    public static Date getEndOfDay(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()),
                ZoneId.systemDefault());
        LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
        return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }

    @Listener(topic = "event:scene.income.create")
    private void generateIncome(SimpleRequest request) {
        Map map = request.getMap();
        OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
        wrapper.setSubscriber("retailOrder.extension.saveIncome");
        wrapper.setAggregateId((String) map.get("RETAIL_ORDER_ID"));
        wrapper.setPayload(JSONObject.toJSONString(map));
        SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);
    }

    @OutboxSubscriber(id = "retailOrder.extension.saveIncome", name = "建行生活零售单生成生成客户返利")
    private void createIncome(OutboxPayloadWrapper outboxPayloadWrapper) throws Exception {
        JSONObject retailOrder = JSON.parseObject(outboxPayloadWrapper.getPayload());
        PartyRole company = partyRoleRepository.findById("1007").get();
        PartyRole partner = partyRoleRepository.findById(retailOrder.getString("CUSTOMER_ID")).get();
        Enumeration inComeCategory = enumerationRepository.findById("cost").get();
        Contract contract = contractRepository.findByCompanyAndPartner(company.getId(), partner.getId(), new Date());
        if (contract == null) throw new Exception("未找到有效销售合同");
        Income income = new Income();
        income.setCompany(company);
        income.setPartner(partner);
        income.setInComeCategory(inComeCategory);
        income.setCooperation(contract.getCooperation());
        income.setNote("零售单收款自动生成");
        income.setContract(contract);
        income.setSourceBusinessType(retailOrder.getString("ORDER_TYPE"));
        income.setSourceBusinessKey(retailOrder.getString("RETAIL_ORDER_ID"));
        income.setCreator("system");
        income.setUserId("0");
        income.setIncomeItems(generateIncomeItem(retailOrder.getDoubleValue("ACTUAL_AMOUNT") * retailOrder.getDoubleValue("P001")));
        this.invoke("income.supplier.approveBySystem2", MapUtil.mapped(this.invoke("income.supplier.createBySystem2", MapUtil.mapped(income))));
    }

    private Set<IncomeItem> generateIncomeItem(double actualAmount) {
        IncomeType incomeType = incomeTypeRepository.findById("A02").get();
        Set<IncomeItem> incomeItems = new HashSet();
        IncomeItem incomeItem = new IncomeItem();
        incomeItem.setIncomeType(incomeType);
        incomeItem.setTax(incomeType.getTax());
        incomeItem.setIncomeAmount(actualAmount);
        incomeItem.setStartDate(new Date());
        incomeItem.setEndDate(new Date());
        incomeItems.add(incomeItem);
        return incomeItems;
    }

    public Map findDetailsPlatform(SimpleRequest request) throws ParseException {
        JSONObject json = request.getJO();
        JSONObject conditionModel = json.getJSONObject("conditionModel");
        JSONObject companyJson = conditionModel.getJSONObject("merchant");
        JSONArray condition = json.getJSONArray("condition");

        Map<String, Object> map = extracted(condition); //拼接查询条件

        List<Map> list = getMaps(conditionModel, companyJson, map);//查询数据并且拼接查询条件
        return MapUtil.mapper("content", list);
    }

    private List<Map> getMaps(JSONObject conditionModel, JSONObject companyJson, Map<String, Object> map) throws ParseException {
        List<Map> list1 = (List<Map>) conditionModel.get("expenseItems");
        List<String> stringList = new ArrayList<>();
        list1.forEach(income -> {
            stringList.add(income.get("incomeItemId").toString());
        });

        //拼接查询
        List<IncomeItem> expenses = incomeItemRepository.findAll(JpaDsl.toCriteriaIgnoreNull(
                "income.company.id", "EQ", companyJson.get("id"),
                "income.createDate", "GTE", map.get("createDate") == null ? null : new SimpleDateFormat("yyyy-MM-dd").parse(map.get("createDate").toString()),
                "income.createDate", "LTE", map.get("createDate1") == null ? null : new SimpleDateFormat("yyyy-MM-dd").parse(map.get("createDate1").toString()),
                "income.approveDate", "GTE", map.get("approveDate") == null ? null : new SimpleDateFormat("yyyy-MM-dd").parse(map.get("approveDate").toString()),
                "income.approveDate", "LTE", map.get("approveDate1") == null ? null : new SimpleDateFormat("yyyy-MM-dd").parse(map.get("approveDate1").toString()),
                "income.id", "EQ", map.get("id") == null ? null : map.get("id").toString(),
                "income.state", "EQ", "approve",
                "id", "NIN", stringList.size() < 1 ? null : stringList,
                "startDate", "GTE", map.get("startDate") == null ? null : new SimpleDateFormat("yyyy-MM-dd").parse(map.get("startDate").toString()),
                "endDate", "LTE", map.get("endDate") == null ? null : new SimpleDateFormat("yyyy-MM-dd").parse(map.get("endDate").toString())),
                Sort.by(Sort.Direction.ASC, "incomeType.id","createDate"));

        //拼接返回的数据
        List<Map> list = new ArrayList();
        expenses.forEach(incomeItem -> {
            if ((incomeItem.getRecoveryAmount() + incomeItem.getFreezeAmount()) != incomeItem.getIncomeAmount() || incomeItem.getIncomeAmount() == 0 && incomeItem.isDone() == false) {
                PartyRole one = SpringManager.getBean(PartyRoleRepository.class)
                        .findOne(incomeItem.getIncome().getPartner().getId());
                JSONObject object = new JSONObject();

                object.put("incomeId", incomeItem.getIncome().getId());
                object.put("incomeType", incomeItem.getIncomeType());
                object.put("incomeAmount", "Supplier".equals(one.getRole().getId()) ? incomeItem.getIncomeAmount() * -1 : incomeItem.getIncomeAmount());
                object.put("recoveryAmount", incomeItem.getRecoveryAmount());
                object.put("freezeAmount", incomeItem.getFreezeAmount());
                object.put("startDate", incomeItem.getStartDate());
                object.put("endDate", incomeItem.getEndDate());
                object.put("note", incomeItem.getIncome().getNote());
                object.put("_creator", incomeItem.getIncome().get_creator());
                object.put("approveDate", incomeItem.getIncome().getApproveDate().toString());
                object.put("createDate", incomeItem.getCreateDate().toString());
                object.put("sourceBusinessType", incomeItem.getIncome().getSourceBusinessType());
                object.put("source", incomeItem.getIncome().getSource());
                object.put("incomeItemId", incomeItem.getId());
                object.put("incomeItem", incomeItem);
                list.add(object);
            }
        });
        return list;
    }

    private Map<String, Object> extracted(JSONArray condition) {
        Map<String, Object> map = new HashMap<>();
        //查询条件
        condition.stream().forEach(model -> {
            switch (((JSONObject) model).get("field").toString()) {
                case "id": {
                    map.put("id", ((JSONObject) model).get("value"));
                    break;
                }
                case "startDate": {
                    map.put("startDate", ((JSONObject) model).get("value"));
                    break;
                }
                case "endDate": {
                    map.put("endDate", ((JSONObject) model).get("value"));
                    break;
                }
                case "createDate": {
                    if (map.get("createDate") == null) {
                        map.put("createDate", ((JSONObject) model).get("value"));
                    } else {
                        map.put("createDate1", ((JSONObject) model).get("value"));
                    }

                    break;
                }
                case "approveDate": {
                    if (map.get("approveDate") == null) {
                        map.put("approveDate", ((JSONObject) model).get("value"));
                    } else {
                        map.put("approveDate1", ((JSONObject) model).get("value"));
                    }

                    break;
                }
            }

        });
        return map;
    }

}
